﻿using FlexFlow.Base;
using FlexFlow.Base.File;
using FlexFlow.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FlexFlow.Runtime
{
    /// <summary>
    /// 流程定义管理器
    /// </summary>
    public class ProcessDefineManager : ManagerBase
    {
        /// <summary>
        /// 获取或设置默认的流程定义管理器
        /// </summary>
        public static ProcessDefineManager Default { get; set; }
        /// <summary>
        /// 创建新的流程定义
        /// </summary>
        /// <param name="creator">
        /// 创建者
        /// </param>
        /// <param name="content">
        /// 流程定义内容
        /// </param>
        /// <param name="name">
        /// 流程名称
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult Create(Guid creator, string content, string name)
        {
            if (name.Length - 3 < 0)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080101,
                    Message = "流程名称至少为3位"
                };
            }

            FileDescription des = this.Components.FileDescriptionProvider.Create();
            des.FileName = name;
            des.Path = "ProcessDefines";
            des.Uploader = creator;
            des.Size = content.Length;

            return OperateResult.CheckResult(
                checkResult: this.SaveOrCreate(des, content, false),
                successResult: OperateResult.SuccessResult(),
                failResult: new OperateResult()
                {
                    ResultCode = 0x080102,
                    Message = "操作失败"
                }
                );
        }
        /// <summary>
        /// 取得安装过后的流程实例
        /// </summary>
        /// <param name="procId">流程Id</param>
        /// <returns>操作结果</returns>
        public OperateResult GetProcessById(Guid procId)
        {
            Process proc = this.Components.ProcessProvider.Get(procId);
            if (proc == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080701,
                    Message = "流程ID不存在！"
                };
            }

            return OperateResult.SuccessResult(proc);
        }
        /// <summary>
        /// 保存流程定义
        /// </summary>
        /// <param name="fileId">
        /// 要保存的流程定义的文件ID
        /// </param>
        /// <param name="content">
        /// 要保存的内容
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult Save(Guid fileId, string content)
        {
            FileDescription des = this.Components.FileDescriptionProvider.Get(fileId);
            if (des == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080201,
                    Message = "指定流程描述文件不存在！"
                };
            }

            return OperateResult.CheckResult(
               checkResult: SaveOrCreate(des, content, true),
               successResult: OperateResult.SuccessResult(),
               failResult: new OperateResult()
               {
                   ResultCode = 0x080202,
                   Message = "操作失败"
               }
               );
        }

        /// <summary>
        /// 载入流程定义文件
        /// </summary>
        /// <param name="fileId">
        /// 文件ID
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult Load(Guid fileId)
        {
            FileDescription des = this.Components.FileDescriptionProvider.Get(fileId);
            if (des == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080301,
                    Message = "指定流程描述不存在！"
                };
            }
            Stream stream = this.Components.PhysicalFileManager.OpenFile(des, FileOpenMode.Read);
            if (stream == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080302,
                    Message = "指定流程描述文件无法被打开！"
                };
            }
            using (stream)
            {
                using (StreamReader reader = new StreamReader(stream))
                {
                    string content = reader.ReadToEnd();
                    return OperateResult.SuccessResult(content);
                }
            }
        }



        /// <summary>
        /// 保存或创建指定文件并且追加或覆盖内容为content
        /// </summary>
        /// <param name="des">
        /// 要操作的文件描述
        /// </param>
        /// <param name="content">
        /// 要追加或覆盖的文件内容
        /// </param>
        /// <param name="resultCodeStart">
        /// 用来纠正resultCode的开始值
        /// </param>
        /// <param name="isSave">
        /// 是否是保存文件内容
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        /// <remarks>
        /// 本操作占用3个错误代码
        /// </remarks>
        private OperateResult SaveOrCreate(FileDescription des, string content, bool isSave)
        {
            Stream fs = this.Components.PhysicalFileManager.OpenFile(des, FileOpenMode.Write);
            if (fs == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080401,
                    Message = "打开文件失败"
                };
            }
            using (fs)
            {
                using (StreamWriter writer = new StreamWriter(fs))
                {
                    writer.Write(content);
                    writer.Flush();
                }
            }
            if (!isSave)
            {
                if (!this.Components.FileDescriptionProvider.Add(des))
                {
                    this.Components.PhysicalFileManager.DeleteFile(des);
                    return new OperateResult()
                    {
                        ResultCode = 0x080402,
                        Message = "插入文件描述失败"
                    };
                }
            }
            else
            {
                if (!this.Components.FileDescriptionProvider.UpdateModifyTime(des.Identity, DateTime.Now))
                {
                    return new OperateResult()
                    {
                        ResultCode = 0x080403,
                        Message = "更新文件修改日期失败"
                    };
                }
            }


            return OperateResult.SuccessResult(des.Identity);
        }
        /// <summary>
        /// 将指定文件加入流程安装队列
        /// </summary>
        /// <param name="installerId">
        /// 流程安装者ID
        /// </param>
        /// <param name="fileId">
        /// 要安装的流程文件ID
        /// </param>
        /// <param name="procName">
        /// 流程名称
        /// </param>
        /// <returns>
        /// 操作结果
        /// </returns>
        public OperateResult InstallProc(Guid installerId, Guid fileId, string procName)
        {
            //流程版本号
            string version = "";

            if (procName == string.Empty)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080501,
                    Message = "目标流程名称不能为空！"
                };
            }
            FileDescription des = this.Components.FileDescriptionProvider.Get(fileId);
            if (des == null)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080502,
                    Message = "指定文件描述不存在！"
                };
            }
            if (des.Path != "ProcessDefines")
            {
                return new OperateResult()
                {
                    ResultCode = 0x080503,
                    Message = "文件访问违规！"
                };
            }
            if (!this.Components.PhysicalFileManager.FileExists(des))
            {
                return new OperateResult()
                {
                    ResultCode = 0x080504,
                    Message = "指定文件已从磁盘移除！"
                };
            }
            Process installedProc = this.Components.ProcessProvider.GetByFileId(fileId, ProcessState.Installed);
            if (installedProc != null)
            {
                //取得文件对应的流程最大版本号
                version = this.GetInformation("FlexFlow/VersionControl/Process/" + fileId + "/", "CurrentVersion", "0");
                if (version == null)
                {
                    return new OperateResult()
                    {
                        ResultCode = 0x080505,
                        Message = "创建版本失败！"
                    };
                }
                //版本号+1
                version = (int.Parse(version) + 1).ToString();
                if (!this.SetInformation("FlexFlow/VersionControl/Process/" + fileId + "/", "CurrentVersion", version))
                {
                    return new OperateResult()
                    {
                        ResultCode = 0x080505,
                        Message = "更新版本失败！"
                    };
                }
                if (!this.Components.ProcessProvider.UpdateState(installedProc.Identity, ProcessState.Abandoned, "已有新版本安装"))
                {
                    return new OperateResult()
                    {
                        ResultCode = 0x080505,
                        Message = "更新旧的流程状态失败！"
                    };
                }
            }

            if (!this.Components.FileDescriptionProvider.UpdateTag(des.Identity, "Default:等待安装"))
            {
                return new OperateResult()
                {
                    ResultCode = 0x080506,
                    Message = "更新文件备注失败！"
                };
            }

            Process proc = this.Components.ProcessProvider.Create();
            proc.Installer = installerId;
            proc.Name = procName;
            proc.PhysicalFileId = fileId;
            proc.Version = version;
            proc.State = ProcessState.Created;
            bool res = this.Components.ProcessProvider.Add(proc);

            if (!res)
            {
                return new OperateResult()
                {
                    ResultCode = 0x080507,
                    Message = "创建流程失败！"
                };
            }

            if (!this.SetInformation("FlexFlow/VersionControl/Process/" + fileId + "/", version, proc.Identity.ToString()))
            {
                return new OperateResult()
                {
                    ResultCode = 0x080508,
                    Message = "添加版本失败！"
                };
            }

            BuildService.ProcessInstaller.Default.Start();

            return OperateResult.SuccessResult();
        }
        /// <summary>
        /// 取得指定文件安装后的流程Id
        /// </summary>
        /// <param name="fileId">
        /// 文件Id
        /// </param>
        /// <returns>
        /// 安装后的流程Id
        /// </returns>
        public OperateResult GetInstalledProcIdByFileId(Guid fileId)
        {
            Process proc = this.Components.ProcessProvider.GetByFileId(fileId, ProcessState.Installed);
            if (proc == null)
            {
                return new OperateResult() { ResultCode = 080601, Message = "指定文件对应的流程不存在！" };
            }
            return OperateResult.SuccessResult(proc.Identity);
        }
        static ProcessDefineManager()
        {
            Default = new ProcessDefineManager();
        }
    }
}
